#include <fstream>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include "decoder.h"
#include "header.h"

using namespace std;

Decoder::Decoder(const char* infile) {
	ifstream in(infile);
	if (!in) {
		cout<<"Cannot open "<<infile<<", Exit"<<endl;
		exit(1);
	}
	
	string buffer;
	vector<bool> cw;
	vector<LUT>* oref;
	vector<BaseCol>* bptr;
	while (getline(in, buffer)){
		if (buffer[0] == '*') {
			break;
		}

		cw.clear();
		for (int i=2; i<buffer.size(); i++) {
			if (buffer[i] == '0')
				cw.push_back(false);
			else
				cw.push_back(true);
		}

		if (cw[0] == false) {
			oref = &oleft;
			bptr = &lBase;
		} else {
			oref = &oright;
			bptr = &rBase;
		}
		int idx = lmbc(cw,0);
		if (idx > oref->size()) {
			for (int i=oref->size(); i<idx-1; i++) {
				LUT temp;
				BaseCol tembc;
				oref->push_back(temp);
				bptr->push_back(tembc);
			}
			LUT newPart;
			newPart[cw] = buffer[0];
			oref->push_back(newPart);
			BaseCol newBase;
			newBase.L=cw.size();
			bptr->push_back(newBase);
		//cout<<"["<<orig_Part[idx-1][cw]<<"]"<<endl;
		} else {
			(*oref)[idx-1][cw] = buffer[0];
			if (cw.size() > (*bptr)[idx-1].L)
				(*bptr)[idx-1].L = cw.size();
		}
	}
	/* till now, the oleft and oright are set */
	
	for (int i=0; i<oleft.size(); i++) {
		LUT::iterator it = oleft[i].begin();
		/* set Oarray */
		lBase[i].O = &oleft[i];
		/* set FC bit seq */
		vector<bool> temp =it->first;
		for(int j=temp.size(); j<lBase[i].L; j++) {
			temp.push_back(false);
		}
		lBase[i].F = temp;
		/* set indexO */
		while (it != oleft[i].end()) {
			vector<bool> curcode = it->first;
			int curid = norm(it->first, lBase[i].L-(it->first).size());
			int dupl = 1;
			++it;
			if (it !=  oleft[i].end()) {
				int nextid = norm(it->first, lBase[i].L-(it->first).size());
				dupl = nextid-curid;
			}
			for (int j=0; j<dupl; j++) {
				(lBase[i].indexO).push_back(curcode);
			}
		}
	}

	for (int i=0; i<oright.size(); i++) {
		LUT::iterator it = oright[i].begin();
		rBase[i].O = &oright[i];
		vector<bool> temp =it->first;
		for(int j=temp.size(); j<rBase[i].L; j++) {
			temp.push_back(false);
		}
		rBase[i].F = temp;
		/* set indexO */
		while (it != (oright[i].end())) {
			vector<bool> curcode = it->first;
			int curid = norm(it->first, rBase[i].L-(it->first).size());
			int dupl = 1;
			++it;
			if (it != oright[i].end()) {
				int nextid = norm(it->first, rBase[i].L-(it->first).size());
				dupl = nextid-curid;
			}
			for (int j=0; j<dupl; j++) {
				(rBase[i].indexO).push_back(curcode);
			}
		}
	}
	/* till now, the lBase and rBase are set */

	#ifndef DEC_DIS_
	cout<<"left partitions:"<<endl;
	for (int i=0; i<lBase.size(); i++) {
		LUT::iterator it = lBase[i].O->begin();
		cout<<"partition "<<i+1<<", L="<<lBase[i].L<<endl;
		cout<<"FC="<<lBase[i].F<<endl;
		while (it != lBase[i].O->end()) {
			cout<<"["<<it->second<<"]: "<<it->first<<endl;
			++it;
		}
		//for(int j=0; j<lBase[i].indexO.size(); j++)
		//	cout<<lBase[i].indexO[j]<<endl;
	}

	cout<<"right partitions:"<<endl;
	for (int i=0; i<oright.size(); i++) {
		LUT::iterator it = rBase[i].O->begin();
		cout<<"partition "<<i+1<<", L="<<rBase[i].L<<endl;
		cout<<"FC="<<rBase[i].F<<endl;
		while (it != rBase[i].O->end()) {
			cout<<"["<<it->second<<"]: "<<it->first<<endl;
			++it;
		}
		//for(int j=0; j<rBase[i].indexO.size(); j++)
		//	cout<<rBase[i].indexO[j]<<endl;

	}
	#endif
}

int Decoder::lmbc(const vector<bool>& vec, int pos) {
	int i=0;
	for (i=1; i<vec.size()-pos; i++) {
		if (vec[i+pos-1] != vec [i+pos])
			return i;
	}
	return i;
}

vector<bool> Decoder::fkb(const vector<bool>& vec, int pos, int len) {
	vector<bool> temp;
	if (len > vec.size()-pos) /* this should never happen in normal condition */
		return vec;
	for (int i=pos; i<len+pos; i++) {
		temp.push_back(vec[i]);
	}
	return temp;
}

void Decoder::decode (const char* filename) {
	ifstream in(filename);
	if (!in) {
		cout<<"Unable to open file: "<<filename<<endl;
		exit(1);
	}
	
	string buffer;
	getline(in, buffer);
	while(buffer[1] != '*') {
		getline(in, buffer);
	}
	
	cout<<"decoding:"<<endl;
	while(getline(in, buffer)) {
		if (buffer[0] != '0' && buffer[0] != '1')
			continue;
		vector<bool> bit_stream;
		for(int i=0; i<buffer.size(); i++) {
			if (buffer[i] == '0')
				bit_stream.push_back(false);
			else
				bit_stream.push_back(true);
		}
		/* got the bit stream for an encoded line */
		getSymbol(bit_stream,0);
		cout<<endl;
	}
}

void Decoder::getSymbol (const vector<bool>& bit_stream, int ptr) {
	if (ptr >= bit_stream.size())
		return;
	vector<BaseCol>* baseArray;
	int tmax = 0;
	if(bit_stream[ptr] == false) {
		baseArray = &lBase;
		tmax = lBase.size();
	} else {
		baseArray = &rBase;
		tmax = rBase.size();
	}
	int subtree_id = min(tmax, lmbc(bit_stream, ptr));
	//cout<<"stid "<<lmbc(bit_stream, ptr)<<endl;
	int symbol_id;
	vector<bool> C;
	C=fkb(bit_stream, ptr, (*baseArray)[subtree_id-1].L);
	symbol_id = norm(C)-norm((*baseArray)[subtree_id-1].F);
	symbol_id = min(symbol_id, (int)((*baseArray)[subtree_id-1].indexO.size()-1));
	//cout<<"C="<<C<<", FC="<<(*baseArray)[subtree_id-1].F<<", index="<<symbol_id<<endl;
	vector<bool> index = (*baseArray)[subtree_id-1].indexO[symbol_id];
	//cout<<"coedword: "<<index<<endl;
	cout<<(*(*baseArray)[subtree_id-1].O)[index];
	getSymbol(bit_stream, ptr+index.size());
}
